import numpy as np
import pandas as pd
from tqdm import tqdm
import matplotlib.pyplot as plt
import statsmodels.api as sm
from collections import Counter
import seaborn as sns
import logging
logging.basicConfig(filename='logging/output.log',filemode='w',format='%(asctime)s,\n,%(levelname)s:%(message)s',level=logging.INFO)

class SimpleAnalysis(object):

    def __init__(self, factor, ret, freq):
        
        self.factor = factor
        self.ret = ret
        self.freq = freq

    def IC_ana(self,type):
        IC = self.factor.corrwith(self.ret, axis = 1, method = type).dropna() 
        return IC

    def ana_IC_indicator(self, type='spearman', id='factor'):
    # 计算整体IC指标
        IC_Series = self.IC_ana(type)
        IC_Series.name = type
        
        # 计算统计指标
        ic_mean = IC_Series.mean()
        ic_std = IC_Series.std()
        ic_ir = ic_mean / ic_std
        ic_indicators = pd.Series({'ic_mean': ic_mean, 'ic_std': ic_std, 'ic_ir': ic_ir})
        ic_indicators.name = type
        display(ic_indicators)

        # 按年度计算IC指标
        IC_Series.index = pd.to_datetime(IC_Series.index)
        year_mean = IC_Series.groupby(IC_Series.index.year).mean()
        year_std = IC_Series.groupby(IC_Series.index.year).std()
        year_ir = year_mean / year_std

        # 计算累积IC
        ic_cum = IC_Series.cumsum()

        # 创建双轴图表
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(18, 6), gridspec_kw={'width_ratios': [2, 1]})
        
        # 左图：IC时序和累积IC
        ax1.plot(IC_Series, label=f'Monthly IC (Mean={ic_mean:.2f})', color='#1f77b4', linewidth=1.5)
        ax1.set_ylabel('IC Value', fontsize=12)
        ax1.grid(True, linestyle='--', alpha=0.6)
        
        ax1_cum = ax1.twinx()
        ax1_cum.plot(ic_cum, label='Cumulative IC', color='#ff7f0e', linewidth=1.5, alpha=0.7)
        ax1_cum.set_ylabel('Cumulative IC', fontsize=12)
        
        ax1.set_title(f'{id} {type.upper()} IC Series', fontsize=14)
        ax1.legend(loc='upper left')
        ax1_cum.legend(loc='upper right')
        plt.setp(ax1.get_xticklabels(), rotation=45, ha='right')

        # 右图：年度IC条形图
        colors = ['#4c72b0' if x > 0 else '#c44e52' for x in year_mean.values]
        ax2.bar(year_mean.index.astype(str), year_mean.values, color=colors, alpha=0.7)
        
        # 添加数值标签
        for i, (mean, ir) in enumerate(zip(year_mean, year_ir)):
            ax2.text(i, mean/2 if mean > 0 else mean-0.01, 
                    f'{mean:.2f}\nIR={ir:.2f}', 
                    ha='center', va='center', color='white' if mean > 0 else 'black')
        
        ax2.set_title('Annual IC Performance', fontsize=14)
        ax2.grid(True, axis='y', linestyle=':', alpha=0.6)
        ax2.axhline(0, color='black', linewidth=0.8)
        plt.setp(ax2.get_xticklabels(), rotation=45)

        plt.tight_layout()
        plt.show()
        
        return year_mean, year_ir, ic_indicators



    def cal_quantile_daily(self,date):
        daily_factor = self.factor.loc[date]
        daily_ret = self.ret.loc[date] 
        iCodes = daily_factor.dropna().index.intersection(daily_ret.dropna().index)
        factor_values = daily_factor.reindex(iCodes)
        ret_values = daily_ret.reindex(iCodes)
        bins = pd.qcut(factor_values, 10 , labels=False) +1 
        quantiles = {}
        for bin in bins.unique() :
            quantiles[bin] = ret_values[bins == bin].mean()
        quantiles = pd.Series(quantiles)
        return quantiles.sort_index()


    def cal_quantile_ret(self):
        return_Series = {}
        common_date = self.factor.dropna(axis = 0, how = 'all').index.intersection(self.ret.dropna(axis = 0, how = 'all').index)
        for date in tqdm(common_date):
            return_Series[date] = self.cal_quantile_daily(date)
        return_Series = pd.DataFrame(return_Series)
        return return_Series.T
        

    def quantile_ana(self, ret_portfolio):

        if self.freq[0] == 'D':
            indicater_id = ['总收益 (%)','日均收益 (%)', '年化收益 (%)','年化波动率 (%)','夏普比率','卡玛比率','最大回撤 (%)','最长回撤']
            # indicator = []
            all_return = ret_portfolio.iloc[-1] - 1
            year_return = (ret_portfolio.iloc[-1]) ** (252 / ret_portfolio.shape[0]) -1
            day_vol = (ret_portfolio).pct_change().dropna().std()
            year_vol = day_vol * np.sqrt(252)
        elif self.freq[0] == 'M':
            indicater_id = ['总收益 (%)','月均收益 (%)', '年化收益 (%)','年化波动率 (%)','夏普比率','卡玛比率','最大回撤 (%)','最长回撤']
            all_return = ret_portfolio.iloc[-1] - 1
            year_return = (ret_portfolio.iloc[-1]) ** (12 / ret_portfolio.shape[0]) -1
            day_vol = (ret_portfolio).pct_change().dropna().std()
            year_vol = day_vol * np.sqrt(12)
        else:
            raise ValueError('please input D or M')

        #日均收益
        # meanReturn = dayReturn.mean()/period*100.0  #平均
        meanReturn = (ret_portfolio.iloc[-1] ** (1./ret_portfolio.shape[0]) - 1) 


        sharpe = year_return / year_vol if year_vol != 0 else 0

        max_cum = np.maximum.accumulate(ret_portfolio)
        drawback = 1 - ((ret_portfolio)) / max_cum
        max_drawback = np.max(drawback)

        carlmar = year_return / max_drawback

        longest_drawback = Counter(max_cum).most_common()[0][1]
        indicator = [all_return *100,meanReturn *100,  year_return *100, year_vol *100, sharpe, carlmar, max_drawback *100, longest_drawback]
        return (pd.Series(indicator, index = indicater_id))

    def cal_quantile_all_indicators_without_turnover(self, id):
        # 计算每日各分层收益
        factor_ret = self.cal_quantile_ret()
        factor_ret_mean = factor_ret.mean()

        # 强制白色背景样式
        plt.style.use('default')
        plt.rcParams['figure.facecolor'] = 'white'
        plt.rcParams['axes.facecolor'] = 'white'
        
        #######################################
        # 日收益柱状图（白色背景+蓝色系）
        #######################################
        plt.figure(figsize=(12, 6), facecolor='white')
        
        # 蓝色渐变色系 (从浅蓝到深蓝)
        cmap = plt.cm.get_cmap('Blues', len(factor_ret_mean)+3)
        colors = [cmap(i+2) for i in range(len(factor_ret_mean))]  # 跳过最浅的两档
        
        bars = plt.bar(factor_ret_mean.index, factor_ret_mean.values, 
                    color=colors, edgecolor='white', linewidth=1.2)
        
        # 添加数值标签（深蓝色文字）
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2., height,
                    f'{height:.4f}',
                    ha='center', va='bottom', fontsize=10, color='#0B3D91')

        # 设置白色背景元素
        ax = plt.gca()
        ax.set_facecolor('white')
        plt.grid(axis='y', linestyle='--', alpha=0.6, color='lightgray')
        plt.title(f'{id} - Monthly Mean Return by Quantile', fontsize=14, pad=20, color='#0B3D91')
        plt.xlabel('Quantile', fontsize=12, labelpad=10, color='#0B3D91')
        plt.xticks(rotation=45, ha='right')
        plt.ylabel('Mean Return', fontsize=12, labelpad=10, color='#0B3D91')
        
        # 调整坐标轴颜色
        ax.spines['bottom'].set_color('#3A7CB8')
        ax.spines['left'].set_color('#3A7CB8')
        ax.tick_params(axis='x', colors='#3A7CB8')
        ax.tick_params(axis='y', colors='#3A7CB8')
        
        plt.tight_layout()
        plt.show()

        #######################################
        # 计算累计收益指标（白色背景表格）
        #######################################
        factor_cum_ret = (factor_ret+1).cumprod()
        factor_cum_ret = factor_cum_ret.dropna(how='all')
        
        factor_quantiles_ana_result = pd.concat([
            self.quantile_ana(factor_cum_ret[x]) for x in factor_cum_ret.columns], axis=1)
        factor_quantiles_ana_result.columns = list(factor_quantiles_ana_result.columns[:10] + 1)
        
        # 白色背景+蓝色文字表格
        try:
            styled_result = (factor_quantiles_ana_result.style
                            .background_gradient(cmap='Blues', axis=1, vmin=0)
                            .format("{:.4f}")
                            .set_caption(f"Performance Metrics - {id}")
                            .set_properties(**{
                                'color': '#0B3D91',
                                'background-color': 'white'
                            }))
            display(styled_result)
        except:
            display(factor_quantiles_ana_result)
        
        logging.info(f'factor_quantiles_ana_result_without_turnover:\n{factor_quantiles_ana_result}')

        #######################################
        # 3. 累计收益曲线图（纯白背景+蓝色系）
        #######################################
        plt.figure(figsize=(18, 8), facecolor='white')
        
        # 精心调校的蓝色系（NASA风格蓝）
        blue_palette = [
            '#87CEEB',  # 浅天蓝
            '#5D8AA8',  # 空军蓝
            '#1E90FF',  # 道奇蓝
            '#0066CC',  # 深天蓝
            '#003366',  # 午夜蓝
            '#002366',  # 皇家蓝
            '#0B3D91',  # NASA蓝
            '#1560BD',  # 牛仔蓝
            '#1A4F8B',  # 东方蓝
            '#1C39BB'   # 波斯蓝
        ]
        
        # 绘制每条曲线
        for i, col in enumerate(factor_cum_ret.columns):
            plt.plot(factor_cum_ret.index, factor_cum_ret[col], 
                    label=f'Quantile {col}', 
                    color=blue_palette[i%len(blue_palette)],
                    linewidth=2.5,
                    alpha=0.9)
        
        # 修改 plt.annotate 部分代码（累计收益图中）
        for i, col in enumerate(factor_cum_ret.columns):
            last_val = factor_cum_ret[col].iloc[-1]
            plt.annotate(f'{last_val:.2f}', 
                        xy=(factor_cum_ret.index[-1], last_val),
                        xytext=(10, 0), textcoords='offset points',
                        va='center', fontsize=10, color='#0B3D91',
                        bbox=dict(boxstyle='round,pad=0.3', 
                                fc=(1, 1, 1, 0.8),  # 改为元组格式的RGBA
                                ec='#3A7CB8', 
                                lw=1))


        # 设置纯白背景
        ax = plt.gca()
        ax.set_facecolor('white')
        plt.grid(True, linestyle='--', alpha=0.5, color='lightgray')
        
        # 标题和标签（NASA蓝）
        plt.title(f'{id} - Cumulative Return by Quantile', fontsize=14, pad=20, color='#0B3D91')
        plt.xlabel('Date', fontsize=12, labelpad=10, color='#0B3D91')
        plt.xticks(factor_cum_ret.index[::60], rotation=45, ha='right')
        plt.ylabel('Cumulative Return', fontsize=12, labelpad=10, color='#0B3D91')
        
        # 图例设置（白色背景+蓝色边框）
        legend = plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left', 
                        borderaxespad=0., framealpha=1,
                        facecolor='white', edgecolor='#3A7CB8',
                        title='Quantiles', title_fontsize=11)
        plt.setp(legend.get_title(), color='#0B3D91')
        for text in legend.get_texts():
            text.set_color('#0B3D91')
        
        # 坐标轴样式
        ax.spines['bottom'].set_color('#3A7CB8')
        ax.spines['left'].set_color('#3A7CB8')
        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)
        ax.tick_params(axis='x', colors='#3A7CB8')
        ax.tick_params(axis='y', colors='#3A7CB8')
        
        plt.tight_layout()
        plt.show()

    # 计算换手率
    def cal_turnover(self,num):
        bins = self.factor.apply(lambda x: pd.qcut(x, 10, labels= False, duplicates = 'drop'), axis = 1) +1
        fac_num = self.factor[bins == num]
        # commonfactor = up_factor[up_factor.notna() & ret.notna()]
        fac_num_shift = fac_num.shift(1)
        same_stocks = fac_num[fac_num_shift.notna()].count(axis = 1)
        stock_before = fac_num_shift.count(axis = 1)
        tr = 1 - same_stocks / stock_before
        tr.name = num
        return tr.fillna(0)
        

    def cal_quantile_all_indicators_with_turnover(self, id):
        # 设置白色背景样式
        plt.style.use('default')
        plt.rcParams['figure.facecolor'] = 'white'
        plt.rcParams['axes.facecolor'] = 'white'
        
        factor_ret = self.cal_quantile_ret()
        turnovre_ratio = pd.concat([self.cal_turnover(num) for num in range(1,11)], axis=1)

        #######################################
        # 1. 换手率曲线图（蓝色系）
        #######################################
        plt.figure(figsize=(18, 6), facecolor='white')
        
        # 使用NASA蓝色系
        line_colors = ['#1E90FF', '#0B3D91']  # 浅蓝和深蓝
        
        for i, col in enumerate([1, 10]):
            plt.plot(turnovre_ratio.index, turnovre_ratio[col], 
                    color=line_colors[i],
                    linewidth=2,
                    label=f'Quantile {col}')

        ax = plt.gca()
        ax.set_facecolor('white')
        plt.grid(True, linestyle='--', alpha=0.5, color='lightgray')
        plt.title(f'{id} - Turnover Ratio (Quantile 1 & 10)', fontsize=14, pad=20, color='#0B3D91')
        plt.xlabel('Date', fontsize=12, labelpad=10, color='#0B3D91')
        plt.xticks(turnovre_ratio.index[::60], rotation=45, ha='right')
        plt.ylabel('Turnover Ratio', fontsize=12, labelpad=10, color='#0B3D91')
        
        # 添加最后值标注
        for i, col in enumerate([1, 10]):
            last_val = turnovre_ratio[col].iloc[-1]
            plt.annotate(f'{last_val:.2%}', 
                        xy=(turnovre_ratio.index[-1], last_val),
                        xytext=(10, 0), textcoords='offset points',
                        va='center', fontsize=10, color=line_colors[i],
                        bbox=dict(boxstyle='round,pad=0.3', 
                                fc=(1, 1, 1, 0.8),
                                ec=line_colors[i],
                                lw=1))
        
        legend = plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left',
                        facecolor='white', edgecolor='#3A7CB8',
                        title='Quantiles', title_fontsize=11)
        plt.setp(legend.get_title(), color='#0B3D91')
        plt.tight_layout()
        plt.show()

        #######################################
        # 2. 考虑费用后的收益柱状图
        #######################################
        # 计算交易费用
        trade_fee = 2 * turnovre_ratio * 0.0003 + 0.0005 * turnovre_ratio
        factor_ret_fee = factor_ret - trade_fee
        factor_ret_fee_mean = factor_ret_fee.mean()

        plt.figure(figsize=(12, 6), facecolor='white')
        
        # 蓝色渐变色柱状图
        cmap = plt.cm.get_cmap('Blues', len(factor_ret_fee_mean)+3)
        colors = [cmap(i+2) for i in range(len(factor_ret_fee_mean))]
        
        bars = plt.bar(factor_ret_fee_mean.index, factor_ret_fee_mean.values,
                    color=colors, edgecolor='white', linewidth=1.2)
        
        # 添加数值标签
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2., height,
                    f'{height:.4f}',
                    ha='center', va='bottom', fontsize=10, color='#0B3D91')

        ax = plt.gca()
        ax.set_facecolor('white')
        plt.grid(axis='y', linestyle='--', alpha=0.6, color='lightgray')
        plt.title(f'{id} - Mean Return After Fees', fontsize=14, pad=20, color='#0B3D91')
        plt.xlabel('Quantile', fontsize=12, labelpad=10, color='#0B3D91')
        plt.xticks(rotation=45)
        plt.ylabel('Mean Return', fontsize=12, labelpad=10, color='#0B3D91')
        plt.tight_layout()
        plt.show()

        #######################################
        # 3. 累计收益曲线及分析
        #######################################
        factor_cum_ret = (factor_ret_fee+1).cumprod()
        factor_cum_ret = factor_cum_ret.dropna(how='all')
        
        # 性能指标分析
        factor_quantiles_ana_result = pd.concat([
            self.quantile_ana(factor_cum_ret[x]) for x in factor_cum_ret.columns], axis=1)
        factor_quantiles_ana_result.columns = factor_quantiles_ana_result.columns[:10] + 1
        
        # 美化表格输出
        try:
            styled_result = (factor_quantiles_ana_result.style
                            .background_gradient(cmap='Blues', axis=1, vmin=0)
                            .format("{:.4f}")
                            .set_caption(f"Performance Metrics - {id}")
                            .set_properties(**{
                                'color': '#0B3D91',
                                'background-color': 'white'
                            }))
            display(styled_result)
        except:
            display(factor_quantiles_ana_result)
        
        logging.info(f'factor_quantiles_ana_result_with_turnover:\n{factor_quantiles_ana_result}')

        #######################################
        # 4. 累计收益曲线图（蓝色系）
        #######################################
        plt.figure(figsize=(18, 8), facecolor='white')
        
        # 蓝色调色板（10种蓝色）
        blue_palette = [
            '#87CEEB', '#5D8AA8', '#1E90FF', '#0066CC', 
            '#003366', '#002366', '#0B3D91', '#1560BD',
            '#1A4F8B', '#1C39BB'
        ]
        
        for i, col in enumerate(factor_cum_ret.columns):
            plt.plot(factor_cum_ret.index, factor_cum_ret[col], 
                    color=blue_palette[i],
                    linewidth=2.5,
                    alpha=0.9,
                    label=f'Quantile {col}')
        
        # 添加最后值标注
        for i, col in enumerate(factor_cum_ret.columns):
            last_val = factor_cum_ret[col].iloc[-1]
            plt.annotate(f'{last_val:.2f}', 
                        xy=(factor_cum_ret.index[-1], last_val),
                        xytext=(10, 0), textcoords='offset points',
                        va='center', fontsize=10, color=blue_palette[i],
                        bbox=dict(boxstyle='round,pad=0.3', 
                                fc=(1, 1, 1, 0.8),
                                ec=blue_palette[i],
                                lw=1))

        ax = plt.gca()
        ax.set_facecolor('white')
        plt.grid(True, linestyle='--', alpha=0.5, color='lightgray')
        plt.title(f'{id} - Cumulative Return After Fees', fontsize=14, pad=20, color='#0B3D91')
        plt.xlabel('Date', fontsize=12, labelpad=10, color='#0B3D91')
        plt.xticks(factor_cum_ret.index[::60], rotation=45, ha='right')
        plt.ylabel('Cumulative Return', fontsize=12, labelpad=10, color='#0B3D91')
        
        legend = plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left',
                        facecolor='white', edgecolor='#3A7CB8',
                        title='Quantiles', title_fontsize=11)
        plt.setp(legend.get_title(), color='#0B3D91')
        plt.tight_layout()
        plt.show()

        return turnovre_ratio.mean()
